#include <Kharlia/Engine/Common.h>
#include <Kharlia/Engine/Init.h>
#include <Kharlia/Engine/Level.h>

namespace kharlia { namespace engine {

void _InitLevelBindings() {
    def("TileFromCoords", &TileFromCoords);
    def("TileToX", &TileToX);
    def("TileToY", &TileToY);

    class_<FTileLayer, shared_ptr<FTileLayer>, bases<core::CObject>, boost::noncopyable>
        ("FTileLayer", init<>())
        .def(init<FSizeI const&>())
        .def(init<shared_ptr<FTileData>>())
        .def_readonly("TileData", &FTileLayer::mTileData)
        .def_pickle(FTileLayer::Pickler())
        ;

    class_<FTileGroup, shared_ptr<FTileGroup>, bases<core::CObject>, boost::noncopyable>
        ("FTileGroup", init<FSizeI const&>())
        .def_readonly("WIDTH", &FTileGroup::WIDTH)
        .def_readonly("HEIGHT", &FTileGroup::HEIGHT)
        .def("AddLayer", (void (FTileGroup::*)(int))&FTileGroup::AddLayer)
        .def("AddLayer", (void (FTileGroup::*)(int, shared_ptr<FTileLayer>))&FTileGroup::AddLayer)
        .def("GetLayer", &FTileGroup::GetLayer, return_value_policy<copy_const_reference>())
        .add_property("LayerCount", &FTileGroup::GetLayerCount)
        .def_readonly("Size", &FTileGroup::mSize)
        .def_pickle(FTileGroup::Pickler())
        ;

    class_<FLevelLayer, shared_ptr<FLevelLayer>>
        ("FLevelLayer", init<>())
        .def_readwrite("Index", &FLevelLayer::Index)
        .def_readwrite("Name", &FLevelLayer::Name)
        .def_readwrite("Visible", &FLevelLayer::Visible)
        .def_readwrite("NoCollision", &FLevelLayer::NoCollision)
        .def_readwrite("Red", &FLevelLayer::Red)
        .def_readwrite("Green", &FLevelLayer::Green)
        .def_readwrite("Blue", &FLevelLayer::Blue)
        .def_readwrite("Alpha", &FLevelLayer::Alpha)
        .def_readwrite("Color", &FLevelLayer::Color)
        .def_readwrite("Tileset", &FLevelLayer::Tileset)
        .def_pickle(FLevelLayer::Pickler())
        ;

    class_<FTileInfo>
        ("FTileInfo", init<>())
        .add_property("Blocking", &FTileInfo::GetBlocking, &FTileInfo::SetBlocking)
        .add_property("Shape", &FTileInfo::GetShape, &FTileInfo::SetShape)
        ;

    class_<FTileset, shared_ptr<FTileset>>
        ("FTileset", init<>())
        .def(init<str, sint16>())
        .def_readwrite("Name", &FTileset::mName)
        .def_readwrite("Texture", &FTileset::mTexture)
        .def_readwrite("Size", &FTileset::mSize)
        .add_property("TileCount", &FTileset::GetTileCount)
        .add_property("Offset", &FTileset::GetOffset, &FTileset::SetOffset)
        .def("CheckBlocking", &FTileset::CheckBlocking)
        .def("GetTileInfoByIndex", &FTileset::GetTileInfoByIndex, return_internal_reference<>())
        .def("GetTileInfoByCode", &FTileset::GetTileInfoByCode, return_internal_reference<>())
        .def("UpdateTexture", &FTileset::UpdateTexture)
        .setattr("PAGE_WIDTH", FTileset::PAGE_WIDTH)
        .setattr("PAGE_HEIGHT", FTileset::PAGE_HEIGHT)
        .setattr("PAGE_SIZE", FTileset::PAGE_SIZE)
        .def_pickle(FTileset::Pickler())
        ;

    class_<CLevel, bases<core::CObject>, boost::noncopyable>
        ("CLevelBase", init<object, unicode, FSizeI const&>())
        .def_readonly("MAX_WIDTH", &CLevel::MAX_WIDTH)
        .def_readonly("MAX_HEIGHT", &CLevel::MAX_HEIGHT)
        .add_property("World", &CLevel::GetWorld)
        .def_readonly("Size", &CLevel::mSize)
        .def_readonly("TileGroupSize", &CLevel::mTileGroupSize)
        .add_property("TileGroupCount", &CLevel::GetTileGroupCount)
        .add_property("LayerCount", &CLevel::GetLayerCount)
        .def_readonly("Name", &CLevel::mName)
        .def_readonly("GUID", &CLevel::mGUID)
        .add_property("ActorCount", &CLevel::GetActorCount)
        .add_property("GameStarted", &CLevel::GetGameStarted)
        .add_property("Game", &CLevel::GetGame)
        .def("__del__", &CLevel::Finalize)
        .def("Clear", &CLevel::ClearImpl)
        .def("Test", &CLevel::Test)
        .def("Tick", &CLevel::Tick)
        .def("TickActors", &CLevel::TickActors)
        .def("AddedToWorld", &CLevel::AddedToWorld)
        .def("RemovedFromWorld", &CLevel::RemovedFromWorld)
        .def("GetActorByTag", &CLevel::GetActorByTag)
        .def("GetActorsByTag", &CLevel::GetActorsByTagPy)
        .def("GetActorByID", &CLevel::GetActorByID)
        .def("GetActorByName", &CLevel::GetActorByName)
        .def("GetActorByIndex", &CLevel::GetActorByIndex, return_value_policy<return_by_value>())
        .def("CreateActor", &CLevel::CreateActorImpl)
        .def("DestroyActor", &CLevel::DestroyActorImpl)
        .def("_AddActor", &CLevel::AddActor)
        .def("_RemoveActor", &CLevel::RemoveActor, (arg("actor"), arg("id")=0))
        .def("CreateID", &CLevel::CreateID)
        .def("RenameActor", &CLevel::RenameActor)
        .def("ClearActors", &CLevel::ClearActors)
        .def("StartGame", &CLevel::StartGame)
        .def("StopGame", &CLevel::StopGame)
        .def("CreateLayer", &CLevel::CreateLayer)
        .add_property("CollisionLayer", &CLevel::GetCollisionLayer, &CLevel::SetCollisionLayer)
        .def("BuildTileCollisionPolygons", &CLevel::BuildTileCollisionPolygonsPy)
        .def("GetTileGroup", (shared_ptr<FTileGroup> const& (CLevel::*)(uint) const)&CLevel::GetTileGroup, return_value_policy<copy_const_reference>())
        .def("GetTileGroup", (shared_ptr<FTileGroup> const& (CLevel::*)(FVector2I const&) const)&CLevel::GetTileGroup, return_value_policy<copy_const_reference>())
        .def("GetTileGroupAt", (shared_ptr<FTileGroup> const& (CLevel::*)(FVector2I const&) const)&CLevel::GetTileGroupAt, return_value_policy<copy_const_reference>())
        .def("GetTileGroupAt", (shared_ptr<FTileGroup> const& (CLevel::*)(FVector2F const&) const)&CLevel::GetTileGroupAt, return_value_policy<copy_const_reference>())
        .def("GetLayer", &CLevel::GetLayer)
        .def("GetTileInfo", (FTileInfo const* (CLevel::*)(int, FVector2I const&) const)&CLevel::GetTileInfo, return_internal_reference<>())
        .def("SetTiles", (void (CLevel::*)(int, tile_t))&CLevel::SetTiles)
        .def("SetTiles", (void (CLevel::*)(int, FVector2I const&, FSizeI const&, tile_t))&CLevel::SetTiles)
        .def("SetTiles", (void (CLevel::*)(int, FVector2I const&, shared_ptr<FTileData>))&CLevel::SetTiles)
        .def("OnCreated", &CLevel::OnCreatedImpl)
        .def("OnDestroyed", &CLevel::OnDestroyedImpl)
        .def("SetPlayerControllerClass", &CLevel::SetPlayerControllerClass).staticmethod("SetPlayerControllerClass")
        .def("GetActorClass", &CLevel::GetActorClass).staticmethod("GetActorClass")
        .def("SetActorClass", &CLevel::SetActorClass).staticmethod("SetActorClass")
        .def_pickle(CLevel::Pickler())
        .setattr("PRE_TICK_GROUP", CLevel::PRE_TICK_GROUP)
        .setattr("TICK_GROUP", CLevel::TICK_GROUP)
        .setattr("POST_TICK_GROUP", CLevel::POST_TICK_GROUP)
        .setattr("GROUP_COUNT", CLevel::GROUP_COUNT)
        ;

    KH_IMPL_GC(CLevel);
    RegisterPtrConverter<CLevel>();
}

}}